from django.core.mail import EmailMessage as _EmailMessage, make_msgid
from email.Utils import formatdate
from django_smtpd.client import default_connection
import django_smtpd
import email, re
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from django.conf import settings
from django.utils.encoding import smart_str, force_unicode


class ContentNotFound(Exception): pass

def decode_body(msg, charset=None):
  s = msg.get_payload(decode=True)
  if not charset:
    charset = msg.get_content_charset()
  return force_unicode(s, charset)

class EmailMessage(_EmailMessage):
  def __init__(self, *args, **kwargs):
    if not 'connection' in kwargs:
      kwargs['connection'] = default_connection()
    super(EmailMessage, self).__init__(*args, **kwargs)

  @staticmethod
  def from_message_data(message):
    msg = email.message_from_string(message)
    for header, value in msg.items(): # remove multi-lines
      s, _ = re.subn("\r?\n", " ", value)
      msg.replace_header(header, s)
    def get_message_body():
      charsets = msg.get_charsets()
      if not msg.is_multipart():
        return decode_body(msg, charsets[0])
      else:
        #find the text/plain
        for m in msg.walk():
          charset = charsets.pop(0)
          if m.get_content_type() == 'text/plain':
            return decode_body(m, charset)
        raise ContentNotFound
    msg_subject = msg['Subject']
    msg_body = get_message_body()
    msg_from = msg['From']
    msg_to = msg.get_all('To')
    msg_attachments = None #todo
    msg_headers = dict(msg.items()) #todo: fix duplicate headers
    for header in ['From', 'To', 'Subject']:
      del msg_headers[header]
    m = EmailMessage(subject=msg_subject, body=msg_body, from_email=msg_from, to=msg_to, attachments=msg_attachments,headers=msg_headers)
    return m

  def message(self): #strip the Safe crap
        encoding = self.encoding or settings.DEFAULT_CHARSET
        msg = MIMEText(smart_str(self.body, settings.DEFAULT_CHARSET),
                           self.content_subtype, encoding)
        if self.attachments:
            body_msg = msg
            msg = MIMEMultipart(_subtype=self.multipart_subtype)
            if self.body:
                msg.attach(body_msg)
            for attachment in self.attachments:
                if isinstance(attachment, MIMEBase):
                    msg.attach(attachment)
                else:
                    msg.attach(self._create_attachment(*attachment))
        msg['Subject'] = self.subject
        msg['From'] = self.from_email
        msg['To'] = ', '.join(self.to)

        # Email header names are case-insensitive (RFC 2045), so we have to
        # accommodate that when doing comparisons.
        header_names = [key.lower() for key in self.extra_headers]
        if 'date' not in header_names:
            msg['Date'] = formatdate()
        if 'message-id' not in header_names:
            msg['Message-ID'] = make_msgid()
        for name, value in self.extra_headers.items():
            msg[name] = value
        return msg


  def get_header(self, name):
    name = name.lower()
    for k,v in self.extra_headers.iteritems():
      if k.lower() == name:
        return v
    return ''

  def reply(self, from_email, text, reply_all=False, headers={}):
    new_subject = self.subject
    if not new_subject.startswith("Re:"):
      new_subject = "Re: %s" % new_subject

    new_body = [text, '']
    new_body += [">%s" % line for line in self.body.splitlines()]
    new_body = "\r\n".join(new_body)
    if reply_all:
      new_to = self.recipients()
      if from_email in new_to:
        new_to.remove(from_email)
    else:
      new_to = [self.from_email]
    if not 'user-agent' in headers:
      headers['User-Agent'] = 'django-smtpd v%s' % django_smtpd.__version__
    headers['In-Reply-To'] = self.get_header('Message-ID')
    return EmailMessage(subject=new_subject, body=new_body, from_email=from_email, to=new_to, headers=headers)   
